﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Web.ModelBinding;
using System.Web.Mvc;
using System.Web.Mvc.Fakes;
using System.Web.Routing;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using User.Global.Contracts.Message;
using User.Web.UI.Helper.Messages;
using ModelErrorCollection = System.Web.Mvc.ModelErrorCollection;
using ModelState = System.Web.Mvc.ModelState;
using ModelStateDictionary = System.Web.Mvc.ModelStateDictionary;

namespace User.Web.UI.Tests.Unit.CommonTests
{
    [TestClass]
    public class ShowCustomMessageTest : CommonBaseTest
    {
        private string HtmlCustomMessageTemplate = "<div class=\"{0}\"><button class=\"close\" data-dismiss=\"alert\" type=\"button\">×</button>{1}</div>";

        /// <summary>
        /// "Anzeigen" der Custommessage, wenn keine Messages hinterlegt wurden.
        /// </summary>
        [TestMethod]
        public void ShowCustomMessage_Success_NoMessages()
        {
            using (ShimsContext.Create())
            {
                //.Net Fakes zurückgreifen
                ShimModelStateDictionary.AllInstances.IsValidGet = (p) => true;
                //Es wurden keine Messages abgelegt im TempData.
                AccountController.TempData[CustomMessage.TempMessageString] = null;
                var viewContext = new ViewContext
                {
                    Controller = AccountController,
                    HttpContext = AccountController.HttpContext,
                };
                var mockViewDataContainer = new Mock<IViewDataContainer>();
                mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });
                var mockRouteHandler = new Mock<IRouteHandler>();
                var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });

                //Assert die HTML Rückgabeweerte prüfen
                Assert.AreEqual(helper.ShowCustomMessage().ToHtmlString(), new MvcHtmlString("").ToHtmlString());
            }
        }

        private List<IMessage> GetTestMessages()
        {
            List<IMessage> messages = new List<IMessage>();
            messages.Add(new Message("TestMessageText1", MessageTypes.ok));
            messages.Add(new Message("TestMessageText2", MessageTypes.warning));
            messages.Add(new Message("TestMessageText3", MessageTypes.error));
            messages.Add(new Message("TestMessageText4", MessageTypes.message));
            return messages;
        }

        /// <summary>
        /// Anzeigen von Messages, wenn nur TempdataMessages hinterlegt wurden.
        /// </summary>
        [TestMethod]
        public void ShowCustomMessage_Success_TempDataMessages()
        {
            //Arrange
            using (ShimsContext.Create())
            {
                ShimModelStateDictionary.AllInstances.IsValidGet = (p) => true;
                AccountController.TempData[CustomMessage.TempMessageString] = GetTestMessages();
                var viewContext = new ViewContext
                {
                    Controller = AccountController,
                    HttpContext = AccountController.HttpContext,
                };

                var mockViewDataContainer = new Mock<IViewDataContainer>();
                mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });
                var mockRouteHandler = new Mock<IRouteHandler>();
                var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });

                //Unsere Meldung selbst zusammenbauen
                string testHtml = string.Format(HtmlCustomMessageTemplate, "alert alert-info", "TestMessageText4");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestMessageText3");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-warning", "TestMessageText2");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-success", "TestMessageText1");

                //Assert die Ausgabemeldungen mit einander vergleichen.
                Assert.AreEqual(helper.ShowCustomMessage().ToHtmlString(), testHtml);
            }
        }

        /// <summary>
        /// Ausgeben von Fehlermeldungen die nur über den Modelstate vorhanden sind.
        /// </summary>
        [TestMethod]
        public void ShowCustomMessage_Success_ModelStateErrors()
        {
            using (ShimsContext.Create())
            {
                //Arrange
                //Es wurden keine Messages abgelegt.
                AccountController.TempData[CustomMessage.TempMessageString] = null;
                //Angeben, das ein Modelstate Error aufgetreten ist.
                ShimModelStateDictionary.AllInstances.IsValidGet = (p) => false;
                ShimModelStateDictionary.AllInstances.KeysGet = (p) => new Collection<string>() { "ErrorKeY" };
                ShimModelStateDictionary.AllInstances.TryGetValueStringModelStateOut =
                    delegate(ModelStateDictionary dictionary, string s, out ModelState @out)
                    {
                        @out = new ModelState();
                        return true;
                    };

                //Zwei Fehlermeldungen hinzufügen über die ErrorCollection, diese werden immer als Error ausgegeben.
                ShimModelState.AllInstances.ErrorsGet = (p) => new ModelErrorCollection() { "TestErrorAnzeige1", "TestErrorAnzeige2" };

                var viewContext = new ViewContext
                {
                    Controller = AccountController,
                    HttpContext = AccountController.HttpContext,
                };

                var mockViewDataContainer = new Mock<IViewDataContainer>();
                mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });
                var mockRouteHandler = new Mock<IRouteHandler>();
                var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });

                string testHtml = string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestErrorAnzeige1");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestErrorAnzeige2");

                //Assert
                Assert.AreEqual(helper.ShowCustomMessage().ToHtmlString(), testHtml);
            }
        }

        [TestMethod]
        public void ShowCustomMessage_Success_TempDataAndModelStateErrors()
        {
            using (ShimsContext.Create())
            {
                //Arrange
                //Unsere Testmessages hinterlegen
                AccountController.TempData[CustomMessage.TempMessageString] = GetTestMessages();
                //Ebenfalls noch Error Messages aus dem Modelstate aktivieren
                ShimModelStateDictionary.AllInstances.IsValidGet = (p) => false;
                //ErrorMessages im Modelstate hinzufügen
                ShimModelState.AllInstances.ErrorsGet = (p) => new ModelErrorCollection() { "TestErrorAnzeige1", "TestErrorAnzeige2" };
                ShimModelStateDictionary.AllInstances.KeysGet = (p) => new Collection<string>() { "ErrorKeY" };
                ShimModelStateDictionary.AllInstances.TryGetValueStringModelStateOut =
                    delegate(ModelStateDictionary dictionary, string s, out ModelState @out)
                    {
                        @out = new ModelState();
                        return true;
                    };

                var viewContext = new ViewContext
                {
                    Controller = AccountController,
                    HttpContext = AccountController.HttpContext,
                };
                var mockViewDataContainer = new Mock<IViewDataContainer>();
                mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });
                var mockRouteHandler = new Mock<IRouteHandler>();
                var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });

                //Unsere Meldung selbst zusammenbauen
                string testHtml = string.Format(HtmlCustomMessageTemplate, "alert alert-info", "TestMessageText4");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestMessageText3");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestErrorAnzeige1");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-danger", "TestErrorAnzeige2");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-warning", "TestMessageText2");
                testHtml += string.Format(HtmlCustomMessageTemplate, "alert alert-success", "TestMessageText1");

                //Assert
                Assert.AreEqual(helper.ShowCustomMessage().ToHtmlString(), testHtml);
            }
        }
    }
}
